﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Com.ImYan.FormSkin;
using Com.ImYan.ImMemory;
using System.IO;
using System.Diagnostics;
using System.Reflection;

namespace MemoryPlus
{
    public partial class FrmMain : Form
    {
        #region 属性列表 Properties

        /// <summary>
        /// 配置项
        /// </summary>
        private MemorySetting MemorySetting;

        /// <summary>
        /// 配置文件路径
        /// </summary>
        private string SettingFilePath = Path.Combine(Application.StartupPath, "Setting.XML");

        /// <summary>
        /// 隐藏还是关闭窗口（True=隐藏、False=关闭）
        /// </summary>
        private bool IsHideOrCloseWindow = true;

        /// <summary>
        /// 定义获取CPU使用率的性能计数器
        /// </summary>
        private PerformanceCounter ProcessorUsage;

        /// <summary>
        /// 内存详情列表
        /// </summary>
        private MemoryInfoCollection MemoryInfoList;

        /// <summary>
        /// 上一次自动回收内存的时间
        /// </summary>
        private DateTime LastAutoCleanTime = DateTime.Now;

        /// <summary>
        /// 当低于警告内存标准后，是否进行了回收。
        /// </summary>
        private bool IsCleanedWhenLowMemory = false;
        
        /// <summary>
        /// 低于自动回收内存等级时，是否已经自动回收
        /// </summary>
        private bool IsCleanedByAutoMode = false;

        /// <summary>
        /// 程序启动参数
        /// </summary>
        private string[] StartArguments;

        /// <summary>
        /// 是否执行过启动参数
        /// </summary>
        private bool IsExecuteArgs = false;

        /// <summary>
        /// 执行启动参数的“延迟时间”(单位：秒)
        /// </summary>
        private int ExecuteArgsDelayTime = 2;

        /// <summary>
        /// 停顿几秒之后再构建内存详情选项卡
        /// </summary>
        private int InitMemoryInfoTabPageDelayTime = 8;//每秒走4个单位，8相当于2秒

        #endregion

        #region 构造函数 Structures

        public FrmMain(string[] args)
        {
            InitializeComponent();
            this.StartArguments = args;
        }

        #endregion

        #region 私有方法列表 Private Methods

        /// <summary>
        /// 执行启动参数
        /// </summary>
        private void ExecuteStartArgs()
        {
            if (IsExecuteArgs==false)
            {
                //延迟时间检查
                if (this.ExecuteArgsDelayTime < 0)
                {
                    //标记执行
                    this.IsExecuteArgs = true;
                    //执行
                    foreach (string arg in this.StartArguments)
                    {
                        //参数处理
                        string argResult = arg.Trim().ToUpper();

                        switch (argResult)
                        {
                            case "/S":
                                this.ShowOrHideWindow(false);
                                break;
                        }
                    }
                }
                else
                {
                    //递减
                    this.ExecuteArgsDelayTime--;
                }
            }
        }

        /// <summary>
        /// 应用皮肤
        /// </summary>
        private void ApplySkin()
        {
            FormSkin frmSkin = new FormSkin();
            frmSkin.OutputResources();
            frmSkin.ApplyRandomSkinToForm(this);
            frmSkin.ClearTempFiles();
        }

        /// <summary>
        /// 初始化对象和事件
        /// </summary>
        private void InitDefault()
        {
            //首先读取配置文件
            this.MemorySetting = MemorySettingManager.ReadSetting(this.SettingFilePath);
            //如果为Null,则代表没有配置文件，或者出现错误，则启动默认值
            if (this.MemorySetting == null) this.MemorySetting = new MemorySetting();
            //初始化列表
            this.MemoryInfoList = new MemoryInfoCollection();
            this.MemoryInfoList.MaxCount = 15;//只记录15个
            this.MemoryInfoList.DelayTime = 2;//2秒记录一次
            //订阅回收事件
            MemoryManager.AfterMemoryClean += new AfterMemoryCleanDelegate(MemoryManager内存回收之后_AfterMemoryClean);
            //初始化CPU计时器
            this.InitPerformanceCounter();
            //初始化“封面”面板
            this.InitPanCover();

            //4个计时器初始化动作
            this.tmrMemoryInfo.Tick += new EventHandler(tmrMemoryInfo内存详情计时器_Tick);
            this.tmrCpu.Tick += new EventHandler(tmrCpuCPU占用率计时器_Tick);
            this.tmrProcess.Tick += new EventHandler(tmrProcess进程监视计时器_Tick);
            //通知区域图标计时器
            this.tmrNotifyIcon.Tick += new EventHandler(tmrNotifyIcon显示内存ICON图标计时器_Tick);

            //应用内存配置到界面
            this.SetMemorySettingToControl();
        }

        #region 【配置信息---界面数据】读取及赋值

        /// <summary>
        /// 应用内存配置到界面控件
        /// </summary>
        private void SetMemorySettingToControl()
        {
            try
            {
                if (this.MemorySetting != null)
                {
                    MemorySetting setting = this.MemorySetting;
                    MemoryInfo info = MemoryManager.GetMemoryInfo(MemoryUnitType.M);

                    //一项项的赋值吧，神啊，控件这么多，还好分组了。
                    #region 内存警告配置

                    this.set_MemoryWarningLevel_Low_Num.Maximum = info.dwTotalPhys;
                    this.set_MemoryWarningLevel_Low_Num.Value = setting.MemoryWarningLevel_Low;
                    this.set_MemoryWarningLevel_TooLow_Num.Maximum = setting.MemoryWarningLevel_Low;
                    this.set_MemoryWarningLevel_TooLow_Num.Value = setting.MemoryWarningLevel_TooLow;
                    this.set_AutoCleanMemoryUnderLow_Ckb.Checked = setting.AutoCleanMemoryUnderLow;
                    //this.set_MemoryWarningLevel_Low_Num.Enabled = setting.AutoCleanMemoryUnderLow;
                    //this.set_MemoryWarningLevel_TooLow_Num.Enabled = setting.AutoCleanMemoryUnderLow;

                    #endregion

                    #region 自动回收配置

                    this.set_AutoCleanLevel_Num.Maximum = (info.dwTotalPhys / 2);//自动回收等级最大允许总内存的一半
                    this.set_AutoCleanLevel_Num.Value = setting.AutoCleanLevel;
                    this.set_AutoCleanTimeSpan_Txt.Text = setting.AutoCleanTimeSpan.ToString();
                    this.set_AutoCleanMemoryByTime_Ckb.Checked = setting.AutoCleanMemoryByTime;
                    //this.set_AutoCleanLevel_Num.Enabled = setting.AutoCleanMemoryByTime;
                    //this.set_AutoCleanTimeSpan_Txt.Enabled = setting.AutoCleanMemoryByTime;

                    #endregion

                    #region 通知区域图标配置

                    this.set_WarnningAreaBackColor_Normal_WCS.WarnningColor = setting.IconSetting.WarnningAreaBackColor_Normal;
                    this.set_WarnningAreaBackColor_Low_WCS.WarnningColor = setting.IconSetting.WarnningAreaBackColor_Low;
                    this.set_WarnningAreaBackColor_TooLow_WCS.WarnningColor = setting.IconSetting.WarnningAreaBackColor_TooLow;
                    this.set_BackgroundColor_CST.SelectedColor = setting.IconSetting.BackgroundColor;
                    this.set_ForeColor_CST.SelectedColor = setting.IconSetting.ForeColor;
                    this.set_WarnningAreaBorderWidth_NUM.Value = (decimal)setting.IconSetting.WarnningAreaBorderWidth;
                    this.set_WarnningAreaBorderColor_CST.SelectedColor = setting.IconSetting.WarnningAreaBorderColor;

                    #endregion

                    #region 其他配置项

                    this.set_TopWindow_Ckb.Checked = setting.TopWindow;
                    //启动项
                    this.set_AutoRunAfterSystemStarted_Ckb.Checked=setting.AutoRunAfterSystemStarted;
                    if (this.set_AutoRunAfterSystemStarted_Ckb.Checked)
                        RegistryManager.CheckAutoRun(true);
                    else
                        RegistryManager.DeleteKey();
                    this.set_LogMaxRow_Num.Value = setting.LogMaxRow;

                    #endregion
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("应用内存配置到界面控件时出现错误！\n\n{0}", ex.Message),
                    this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 从界面读取配置
        /// </summary>
        private bool GetMemorySettingFromControl()
        {
            try
            {
                #region 内存警告配置

                this.MemorySetting.MemoryWarningLevel_Low = (int)this.set_MemoryWarningLevel_Low_Num.Value;
                this.MemorySetting.MemoryWarningLevel_TooLow = (int)this.set_MemoryWarningLevel_TooLow_Num.Value;
                this.MemorySetting.AutoCleanMemoryUnderLow = this.set_AutoCleanMemoryUnderLow_Ckb.Checked;

                #endregion

                #region 自动回收配置

                this.MemorySetting.AutoCleanLevel = (int)this.set_AutoCleanLevel_Num.Value;
                this.MemorySetting.AutoCleanTimeSpan = int.Parse(this.set_AutoCleanTimeSpan_Txt.Text);
                this.MemorySetting.AutoCleanMemoryByTime = this.set_AutoCleanMemoryByTime_Ckb.Checked;

                #endregion

                #region 通知区域图标配置

                this.MemorySetting.IconSetting.WarnningAreaBackColor_Normal = this.set_WarnningAreaBackColor_Normal_WCS.WarnningColor;
                this.MemorySetting.IconSetting.WarnningAreaBackColor_Low = this.set_WarnningAreaBackColor_Low_WCS.WarnningColor;
                this.MemorySetting.IconSetting.WarnningAreaBackColor_TooLow = this.set_WarnningAreaBackColor_TooLow_WCS.WarnningColor;
                this.MemorySetting.IconSetting.BackgroundColor = this.set_BackgroundColor_CST.SelectedColor;
                this.MemorySetting.IconSetting.ForeColor = this.set_ForeColor_CST.SelectedColor;
                this.MemorySetting.IconSetting.WarnningAreaBorderWidth = (float)this.set_WarnningAreaBorderWidth_NUM.Value;
                this.MemorySetting.IconSetting.WarnningAreaBorderColor = this.set_WarnningAreaBorderColor_CST.SelectedColor;

                #endregion

                #region 其他配置项

                this.MemorySetting.TopWindow = this.set_TopWindow_Ckb.Checked;
                this.MemorySetting.AutoRunAfterSystemStarted = this.set_AutoRunAfterSystemStarted_Ckb.Checked;
                this.MemorySetting.LogMaxRow = (int)this.set_LogMaxRow_Num.Value;

                #endregion

                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("从界面读取配置时出现错误！\n\n{0}", ex.Message),
                    this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

        #endregion

        #region 进程监视相关

        /// <summary>
        /// 从进程创建列表项
        /// </summary>
        /// <param name="process">进程信息</param>
        /// <returns></returns>
        private ListViewItem CreateProcessItem(Process process)
        {
            ListViewItem item = new ListViewItem(process.Id.ToString());
            item.SubItems.Add(process.ProcessName);
            item.SubItems.Add(((int)(process.WorkingSet64 / 1024F)).ToString("N0") + "K");
            item.Tag = process;

            return item;
        }

        /// <summary>
        /// 检查列表中是否包含某个进程
        /// </summary>
        /// <param name="allProcessList">全部进程</param>
        /// <param name="proFind">要找的进程</param>
        /// <returns></returns>
        private Process CheckProcessExists(List<Process> allProcessList, Process proFind)
        {
            foreach (Process process in allProcessList)
            {
                //只检查名称和源文件
                if (process.ProcessName == proFind.ProcessName &&
                    process.Id == proFind.Id)
                {
                    return process;
                }
            }

            return null;
        }

        /// <summary>
        /// 更新进程列表
        /// </summary>
        /// <param name="allProcessList">总列表</param>
        /// <param name="existProcessItemList">已存在于列表项中的进程</param>
        private void UpdateProcessListView(List<Process> allProcessList, ref List<Process> existProcessItemList)
        {
            //需要删除的项目
            List<ListViewItem> removeList = new List<ListViewItem>();
            foreach (ListViewItem item in this.lsvProcesses.Items)
            {
                Process process = item.Tag as Process;
                Process newProcess = process == null ? null : this.CheckProcessExists(allProcessList, process);
                if (process != null && newProcess != null)
                {
                    //添加到已存在列表
                    existProcessItemList.Add(process);
                    //更新
                    string wokingSetSize = ((int)(newProcess.WorkingSet64 / 1024F)).ToString("N0") + "K";
                    if (wokingSetSize != item.SubItems[2].Text)
                        item.SubItems[2].Text = wokingSetSize;
                }
                else
                {
                    //不存在
                    removeList.Add(item);
                }
            }
            //清除需要删除的项目
            foreach (ListViewItem item in removeList)
            {
                this.lsvProcesses.Items.Remove(item);
            }
        }

        /// <summary>
        /// 向列表添加新项
        /// </summary>
        /// <param name="allProcessList">全部进程</param>
        /// <param name="existProcessItemList">已经存在的（不需要添加已存在，只添加不存在的）</param>
        private void AddProcessToListView(List<Process> allProcessList, List<Process> existProcessItemList)
        {
            foreach (Process process in allProcessList)
            {
                //在“已存在的列表”当然不存在的，就是要添加的
                Process findedProcess = this.CheckProcessExists(existProcessItemList, process);
                if (findedProcess == null)
                {
                    ListViewItem item = this.CreateProcessItem(process);
                    this.lsvProcesses.Items.Add(item);
                }
            }
        }

        /// <summary>
        /// 高亮显示“免收”进程
        /// </summary>
        private void SetNoCleanProcessItemHighLight()
        {
            foreach (ListViewItem item in this.lsvProcesses.Items)
            {
                //改变颜色
                item.ForeColor = this.MemorySetting.NoCleanProcesses.Contains(item.SubItems[1].Text) ?
                    Color.DarkGreen : Color.Black;
                //改变字体
                item.Font = this.MemorySetting.NoCleanProcesses.Contains(item.SubItems[1].Text) ?
                    new Font(item.Font.FontFamily, item.Font.Size, FontStyle.Bold) : this.tabProcesses.Font;
            }
        }

        #endregion

        #region 四个主计时器

        private void tmrCpuCPU占用率计时器_Tick(object sender, EventArgs e)
        {
            //启动暂停间隔
            if (this.InitMemoryInfoTabPageDelayTime >= 0)
            {
                this.InitMemoryInfoTabPageDelayTime--;
                return;
            }
            else
            {
                this.tabMain.Enabled = true;
                this.panCover.Visible = false;
                this.Controls.Remove(this.panCover);
                this.panCover.Dispose();
            }

            try
            {
                //释放以前的
                if (this.panCPU.BackgroundImage != null) this.panCPU.BackgroundImage.Dispose();

                int cpuPercent = (int)this.ProcessorUsage.NextValue();
                Bitmap bmpCPU = ImageTool.GetCpuImage(cpuPercent);
                this.panCPU.BackgroundImage = bmpCPU;
            }
            catch (Exception ex)
            {
                Console.WriteLine("tmrCpuCPU占用率计时器_Tick ERROR:" + ex.Message);
            }
        }

        private void tmrMemoryInfo内存详情计时器_Tick(object sender, EventArgs e)
        {
            MemoryInfo currentInfo = MemoryManager.GetMemoryInfo(MemoryUnitType.M);
            try
            {
                //记住原始图像
                Image oldImage = this.picMemoryInfo.Image;
                Bitmap bmpMemory = ImageTool.GetMomoryInfoImage(currentInfo, this.MemoryInfoList);
                this.picMemoryInfo.Image = bmpMemory;
                //释放对象
                if (oldImage != null) oldImage.Dispose();

                //文本区
                Image textImage = this.picMemoryText.Image;
                MemoryInfo info_BK = MemoryManager.GetMemoryInfo(MemoryUnitType.KB);
                string textInfo = this.GetMemoryInfo(info_BK, MemoryUnitType.KB, true);
                Bitmap bmpText = ImageTool.GetMemoryTextImage(textInfo);
                this.picMemoryText.Image = bmpText;
                if (textImage != null) textImage.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine("tmrMemoryInfo内存详情计时器_Tick ERROR:" + ex.Message);
            }
        }

        private void tmrProcess进程监视计时器_Tick(object sender, EventArgs e)
        {
            //读取全部
            List<Process> allProcessList = new List<Process>(Process.GetProcesses());
            //已经存在的
            List<Process> existProcessItemList = new List<Process>();
            //更新列表
            this.UpdateProcessListView(allProcessList, ref existProcessItemList);
            //根据已经存在的，把不存在的也加上
            this.AddProcessToListView(allProcessList, existProcessItemList);
            //高亮显示“免收”进程
            this.SetNoCleanProcessItemHighLight();
        }

        private void tmrNotifyIcon显示内存ICON图标计时器_Tick(object sender, EventArgs e)
        {
            MemoryInfo currentInfo = MemoryManager.GetMemoryInfo(MemoryUnitType.M);
            //追加到列表
            this.MemoryInfoList.Add(currentInfo);
            try
            {
                Bitmap iconBMP = MemoryIcon.DrawIcon(currentInfo, this.MemorySetting);
                Icon newIcon = Icon.FromHandle(iconBMP.GetHicon());
                this.ntiMain.Icon = newIcon;

                //销毁对象
                MemoryIcon.DestroyIcon(newIcon.Handle);
            }
            catch (Exception ex)
            {
                Console.WriteLine("tmrNotifyIcon显示内存ICON图标计时器_Tick ERROR:" + ex.Message);
            }

            this.ntiMain.Text = this.GetMemoryInfo(MemoryManager.GetMemoryInfo(MemoryUnitType.M), MemoryUnitType.M, false);

            //低内存自动回收。以及定时自动回收
            this.AutoCleanMemory(currentInfo);
            //执行启动参数
            this.ExecuteStartArgs();
        }

        #endregion

        /// <summary>
        /// 初始化CPU计时器
        /// </summary>
        private void InitPerformanceCounter()
        {
            this.ProcessorUsage = new PerformanceCounter();
            this.ProcessorUsage.CategoryName = "Processor";
            this.ProcessorUsage.CounterName = "% Processor Time";
            this.ProcessorUsage.InstanceName = "_Total";
            this.ProcessorUsage.MachineName = ".";
        }

        /// <summary>
        /// 创建内存坐标图的Label标签组
        /// </summary>
        private void InitLabelsOfMemoryInfo()
        {
            //创建多少个
            int numLabel = 5;
            //内存总大小
            uint memoryTotal = MemoryManager.GetMemoryInfo(MemoryUnitType.M).dwTotalPhys;
            //间距
            int distance = (int)(((float)this.picMemoryInfo.Height) / (float)numLabel);
            //显示的数字
            int numText = (int)(((float)memoryTotal) / (float)numLabel);

            for (int i = 0, count = 0; count <= numLabel; i += distance, count++)
            {
                Label labNum = new Label();
                labNum.BackColor = Color.DimGray;
                labNum.ForeColor = Color.Lime;
                labNum.Text = count == 0 ? memoryTotal.ToString() : (numText * (numLabel - count)).ToString();
                labNum.Text = labNum.Text + " M";
                labNum.AutoSize = true;
                labNum.Size = TextRenderer.MeasureText(labNum.Text, labNum.Font);
                labNum.Location = new Point(this.picMemoryInfo.Location.X - labNum.Width,
                    count == numLabel ? picMemoryInfo.Location.Y + picMemoryInfo.Height :
                    picMemoryInfo.Location.Y + count * distance);
                if (count == numLabel) labNum.Top -= labNum.Height;
                this.panMemory.Controls.Add(labNum);
            }
        }

        /// <summary>
        /// 构建“封面”面板
        /// </summary>
        private void InitPanCover()
        {
            try
            {
                Image oldImage = ImageTool.GetCoverBackImage(this.panCover.Size);
                this.panCover.BackgroundImage = oldImage;
            }
            catch (Exception ex)
            {
                Console.WriteLine("构建“封面”面板   出现错误： " + ex.Message);
            }
        }

        /// <summary>
        /// 显示或者隐藏主窗口
        /// </summary>
        private void ShowOrHideWindow()
        {
            this.ShowOrHideWindow(!this.Visible);
        }
        private void ShowOrHideWindow(bool isVisable)
        {
            //是否隐藏
            this.Visible = isVisable;
            //窗口状态
            this.WindowState = this.Visible ? FormWindowState.Normal : FormWindowState.Minimized;
            //停止或者开启工作
            this.SetTabWork(this.Visible ? TabControlAction.Selecting : TabControlAction.Deselected);
        }

        /// <summary>
        /// 内存信息一览
        /// </summary>
        /// <param name="info">内存信息</param>
        /// <param name="allInfo">true:全部信息 false: 精简信息</param>
        /// <returns></returns>
        private string GetMemoryInfo(MemoryInfo info, MemoryUnitType unitType, bool allInfo)
        {
            StringBuilder sb = new StringBuilder();

            if (allInfo) sb.AppendFormat("总物理内存：\r\n{0}{1}\r\n\r\n", info.dwTotalPhys.ToString("N0"), unitType);
            sb.AppendFormat("空闲物理内存：\r\n{0}{1}\r\n\r\n", info.dwAvailPhys.ToString("N0"), unitType);
            if (!allInfo) sb.AppendFormat("使用百分比：\r\n{0}%\r\n\r\n", info.dwMemoryLoad);
            if (allInfo) sb.AppendFormat("总页面文件：\r\n{0}{1}\r\n\r\n", info.dwTotalPageFile.ToString("N0"), unitType);
            if (allInfo) sb.AppendFormat("空闲页面文件：\r\n{0}{1}\r\n\r\n", info.dwAvailPageFile.ToString("N0"), unitType);
            if (allInfo) sb.AppendFormat("总虚拟内存：\r\n{0}{1}\r\n\r\n", info.dwTotalVirtual.ToString("N0"), unitType);
            if (allInfo) sb.AppendFormat("空闲虚拟内存：\r\n{0}{1}\r\n\r\n", info.dwAvailVirtual.ToString("N0"), unitType);
            //if (allInfo) sb.AppendFormat("【系统位数】：\r\n{0}位\r\n", info.dwLength);

            string strInfo = sb.ToString();
            if (!allInfo) strInfo = strInfo.Replace("\r\n\r\n", "\r\n");
            return strInfo.EndsWith("\r\n") ? strInfo.Substring(0, strInfo.Length - (allInfo ? 4 : 2)) : strInfo;
        }

        /// <summary>
        /// 给指定的控件设置背景图像
        /// </summary>
        /// <param name="cl">目标控件</param>
        /// <param name="backImage">图像</param>
        private void SetBackgroundToControl(Control cl, Bitmap backImage)
        {
            try
            {
                if (cl.BackgroundImage != null)
                {
                    cl.BackgroundImage.Dispose();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("给指定的控件设置背景图像 ERROR:" + ex.Message);
            }

            cl.BackgroundImage = backImage;
        }

        private void MemoryManager内存回收之后_AfterMemoryClean(MemoryInfo beforeCleanInfo, MemoryInfo afterCleanInfo)
        {
            if (this.tmrMemoryInfo.Enabled)
            {
                //更新显示
                this.tmrMemoryInfo内存详情计时器_Tick(null, null);
            }

            //写日志
            string logInfo = string.Format("{0} >> 成功回收({1}-{2}){3}M的内存\r\n",
                DateTime.Now,
                afterCleanInfo.dwAvailPhys,
                beforeCleanInfo.dwAvailPhys, 
                (afterCleanInfo.dwAvailPhys - beforeCleanInfo.dwAvailPhys));
            this.txtLog.AppendText(logInfo);
        }

        /// <summary>
        /// 低于警告等级内存自动回收。以及定时自动回收
        /// </summary>
        /// <param name="currentInfo">当前内存信息</param>
        private void AutoCleanMemory(MemoryInfo currentInfo)
        {
            //低于警告等级内存自动回收
            if (currentInfo.dwAvailPhys < this.MemorySetting.MemoryWarningLevel_Low && this.IsCleanedWhenLowMemory == false)
            {
                MemoryManager.CleanMemory(this.MemorySetting.NoCleanProcesses);
                this.IsCleanedWhenLowMemory = true;
            }
            else if (this.IsCleanedWhenLowMemory && currentInfo.dwAvailPhys >= this.MemorySetting.MemoryWarningLevel_Low + 100)//加的这100是缓冲值
            {
                //恢复正常内存范围+100之后，重新标记为“未自动回收”
                this.IsCleanedWhenLowMemory = false;
            }

            //定时回收内存            
            if (this.MemorySetting.AutoCleanMemoryByTime)
            {
                //时间间隔
                TimeSpan span = DateTime.Now.Subtract(this.LastAutoCleanTime);
                if (span.TotalMinutes >= this.MemorySetting.AutoCleanTimeSpan)
                {
                    //超过时间，记录回收时间
                    this.LastAutoCleanTime = DateTime.Now;
                    //自动回收
                    MemoryManager.CleanMemory(this.MemorySetting.NoCleanProcesses);
                }

                //低内存自动回收
                if (this.IsCleanedByAutoMode == false && currentInfo.dwAvailPhys < this.MemorySetting.AutoCleanLevel)
                {
                    this.IsCleanedByAutoMode = true;
                    MemoryManager.CleanMemory(this.MemorySetting.NoCleanProcesses);
                }
                else if (this.IsCleanedByAutoMode && currentInfo.dwAvailPhys >= this.MemorySetting.AutoCleanLevel + 100)//加的这100是缓冲值
                {
                    //恢复正常
                    this.IsCleanedByAutoMode = false;
                }
            }
        }

        #endregion

        #region 窗体事件 Form Events

        #region 主窗体控件

        private void FrmMain_Load(object sender, EventArgs e)
        {
            //应用皮肤
            this.ApplySkin();
            //初始化对象和事件
            this.InitDefault();
        }

        private void FrmMain_Shown(object sender, EventArgs e)
        {
            //内存坐标图的Label标签组
            this.InitLabelsOfMemoryInfo();
            //内存图标显示
            this.tmrNotifyIcon.Enabled = true;
            //默认启动CPU和内存详情的
            this.SetTabWork(TabControlAction.Selecting);
        }

        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            //如果是系统关机，就退出
            if (e.CloseReason == CloseReason.WindowsShutDown) this.IsHideOrCloseWindow = false;

            //是否取消
            e.Cancel = this.IsHideOrCloseWindow;

            //最小化，并隐藏
            if (this.IsHideOrCloseWindow)
            {
                //隐藏
                this.隐藏窗口HToolStripMenuItem_Click(null, null);
            }
            else
            {
                //保存配置
                try
                {
                    MemorySettingManager.SaveSetting(this.MemorySetting, this.SettingFilePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("保存配置出错！\n\n" + ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        #endregion

        #region 顶部主菜单

        #region “文件”菜单

        private void 回收内存RToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MemoryManager.CleanMemory(this.MemorySetting.NoCleanProcesses);
        }

        private void 退出程序EToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("确定要关闭并退出程序吗？\n退出后将不能继续清理优化内存。\n\nYES（是）：退出程序\nNO （否）：隐藏到通知区域\nCANCEL   ：取消此操作", this.Text,
                MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                //退出
                this.IsHideOrCloseWindow = false;
                this.Close();
            }
            else if (result == DialogResult.No)
            {
                this.IsHideOrCloseWindow = true;
                this.ShowOrHideWindow(false);
            }
        }

        #endregion

        #region “视图”菜单

        /// <summary>
        /// 根据选项卡数目构建“视图菜单”
        /// </summary>
        private void InitViewMenu()
        {
            //先清空
            this.视图VToolStripMenuItem.DropDownItems.Clear();

            for (int i = 0; i < this.tabMain.TabPages.Count; i++)
            {
                TabPage page = this.tabMain.TabPages[i];
                ToolStripMenuItem item = new ToolStripMenuItem(page.Text);//, this.imgTabs.Images[page.ImageIndex]);
                item.Checked = this.tabMain.SelectedTab == page;
                item.Tag = page;
                item.Click += new EventHandler(item视图菜单切换选项卡_Click);
                this.视图VToolStripMenuItem.DropDownItems.Add(item);
            }

            //分割线
            ToolStripSeparator separator = new ToolStripSeparator();
            this.视图VToolStripMenuItem.DropDownItems.Add(separator);

            //“隐藏窗口”按钮
            ToolStripMenuItem hideItem = new ToolStripMenuItem("隐藏窗口(&H)", this.btn退出程序.Image);
            hideItem.Click += new EventHandler(隐藏窗口HToolStripMenuItem_Click);
            this.视图VToolStripMenuItem.DropDownItems.Add(hideItem);
        }

        private void item视图菜单切换选项卡_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            if (item != null && item.Tag is TabPage)
            {
                this.tabMain.SelectedTab = item.Tag as TabPage;
            }
        }

        private void 视图VToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            //根据选项卡数目构建“视图菜单”
            this.InitViewMenu();
        }

        private void 隐藏窗口HToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //调用显示或隐藏
            this.ShowOrHideWindow();
        }

        #endregion

        #region “相关网站”菜单

        /// <summary>
        /// 使用IE打开网页
        /// </summary>
        /// <param name="url">网页地址</param>
        public static void RunIE(string url)
        {
            try
            {
                Process.Start("iexplore.exe", url);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("无法打开IE链接：{0}\n\n错误消息是：\n{1}", url, ex.Message), "浏览网页", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void 官方网站ImYanComToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RunIE("http://www.imyan.com");
        }

        private void 龙族联盟论坛DToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RunIE("http://www.chinadforce.com");
        }

        private void 自由联盟论坛FToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RunIE("http://www.ifmu.com.cn");
        }

        #endregion

        #endregion

        #region 选项卡操作

        /// <summary>
        /// 设定当前选项卡内容是否工作
        /// </summary>
        /// <param name="action">动作</param>
        private void SetTabWork(TabControlAction action)
        {
            this.SetTabWork(this.tabMain.SelectedTab, action);
        }

        /// <summary>
        /// 设定选项卡内容是否工作
        /// </summary>
        /// <param name="page">选项卡对象</param>
        /// <param name="action">动作</param>
        private void SetTabWork(TabPage page, TabControlAction action)
        {
            try
            {
                //重新启动工作线程
                if (action == TabControlAction.Selecting || action == TabControlAction.Selected)
                {
                    if (page == this.tabMemoryInfo)
                    {
                        this.tmrCpu.Enabled = true;
                        this.tmrMemoryInfo.Enabled = true;
                    }
                    else if (page == this.tabProcesses)
                    {
                        this.tmrProcess.Enabled = true;
                    }
                    else if (page==this.tabAbout&&string.IsNullOrEmpty(this.labAboutMemoryPlus.Text))
                    {
                        //关于
                        this.picMemoryPlusPNG.Image = Properties.Resources.MemoryPlusIcon_Png;
                        AssemblyName assem=Assembly.GetExecutingAssembly().GetName();
                        this.labAboutMemoryPlus.Text = string.Format("软件名称：{0}\n\n软件版本：{1}\n\n作    者：YanMang\n\n官方网站：ImYan.Com",
                            assem.Name, assem.Version);
                    }
                }
                else//挂起工作线程
                {
                    if (page == this.tabMemoryInfo)
                    {
                        this.tmrCpu.Enabled = false;
                        this.tmrMemoryInfo.Enabled = false;
                    }
                    else if (page == this.tabProcesses)
                    {
                        this.tmrProcess.Enabled = false;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("设定选项卡内容是否工作 ERROR:" + ex.Message);
            }
        }

        private void tabMain_Selecting(object sender, TabControlCancelEventArgs e)
        {
            Console.WriteLine(e.TabPage.Text + " Is " + e.Action.ToString());
            this.SetTabWork(e.TabPage, e.Action);//设定选项卡内容是否工作
        }

        private void tabMain_Deselected(object sender, TabControlEventArgs e)
        {
            Console.WriteLine(e.TabPage.Text + " Is " + e.Action.ToString());
            this.SetTabWork(e.TabPage, e.Action);//设定选项卡内容是否工作
        }

        #region “进程信息”选项卡

        private void lsvProcesses_SelectedIndexChanged(object sender, EventArgs e)
        {
            //高亮色
            Color itemHighLightColor = Color.DarkGreen;

            //单选一条时
            if (this.lsvProcesses.SelectedItems.Count == 1)
            {
                ListViewItem item = this.lsvProcesses.SelectedItems[0];
                //是否允许回收
                this.btn设置是否回收.Text = string.Format("{0}\"免回收\"进程(&R)", this.MemorySetting.NoCleanProcesses.Contains(item.SubItems[1].Text) ? "取消" : "设为");
            }
            //多选时
            else if (this.lsvProcesses.SelectedItems.Count > 1)
            {
                //是否存在“不允许回收”的。
                bool isExistsNotCleanProcess = false;
                foreach (ListViewItem item in this.lsvProcesses.SelectedItems)
                {
                    if (this.MemorySetting.NoCleanProcesses.Contains(item.SubItems[1].Text))
                    {
                        isExistsNotCleanProcess = true;
                        break;
                    }
                }
                //是否允许回收
                this.btn设置是否回收.Text = string.Format("{0}\"免回收\"进程(&R)", isExistsNotCleanProcess ? "取消" : "设为");
            }

            //控件是否可用
            this.btn设置是否回收.Enabled = this.lsvProcesses.SelectedItems.Count > 0;
            this.btn结束进程.Enabled = this.btn设置是否回收.Enabled;
            this.btn立即回收选定进程内存.Enabled = this.btn设置是否回收.Enabled;
        }

        private void btn设置是否回收_Click(object sender, EventArgs e)
        {
            string actionText = this.btn设置是否回收.Text.Substring(0, 2);

            foreach (ListViewItem item in this.lsvProcesses.SelectedItems)
            {
                string processName = item.SubItems[1].Text;
                if (actionText == "取消")
                {
                    this.MemorySetting.NoCleanProcesses.Remove(processName);
                }
                else if (actionText == "设为")
                {
                    this.MemorySetting.NoCleanProcesses.Add(processName);
                }
            }

            //更改按钮显示
            this.lsvProcesses_SelectedIndexChanged(null, null);

            //保存
            MemorySettingManager.SaveSetting(this.MemorySetting, this.SettingFilePath);
        }

        //标题排序
        private void lsvProcesses_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            ColumnHeader column = this.lsvProcesses.Columns[e.Column];
            if (column.Tag == null)
            {
                column.Tag = SortOrder.Ascending;
            }
            else if ((SortOrder)column.Tag == SortOrder.Descending)
            {
                column.Tag = SortOrder.Ascending;
            }
            else if ((SortOrder)column.Tag == SortOrder.Ascending)
            {
                column.Tag = SortOrder.Descending;
            }

            this.lsvProcesses.ListViewItemSorter = new ListViewItemComparer(e.Column);
        }

        private void btn结束进程_Click(object sender, EventArgs e)
        {
            string selectProcessNameList = string.Empty;
            List<int> selectProcessIdList = new List<int>();
            foreach (ListViewItem item in this.lsvProcesses.SelectedItems)
            {
                selectProcessNameList += string.Format("{0},", item.SubItems[1].Text);
                selectProcessIdList.Add(int.Parse(item.SubItems[0].Text));
            }
            selectProcessNameList = selectProcessNameList.EndsWith(",") ? selectProcessNameList.Substring(0, selectProcessNameList.Length - 1) : selectProcessNameList;
            string warningText = string.Format("强制结束进程，可能导致数据丢失！\n\n您确认要关闭所选择的进程吗？？？\n\n您当前选择了 {0} 个进程。\n【{1}】",
                this.lsvProcesses.SelectedItems.Count, selectProcessNameList);
            DialogResult dResult = MessageBox.Show(warningText, "结束进程", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (dResult == DialogResult.Yes)
            {
                foreach (int processID in selectProcessIdList)
                {
                    try
                    {
                        //干掉进程
                        Process.GetProcessById(processID).Kill();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(string.Format("无法关闭进程“{0}”！\n\n{1}", Process.GetProcessById(processID).ProcessName, ex.Message), "结束进程失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }

        private void btn立即回收选定进程内存_Click(object sender, EventArgs e)
        {
            string errorInfo = "回收选定内存时出现错误！\n\n";
            foreach (ListViewItem item in this.lsvProcesses.SelectedItems)
            {
                try
                {
                    int processID = int.Parse(item.SubItems[0].Text);
                    Process process = Process.GetProcessById(processID);
                    if (!MemoryManager.CleanMemory(process))
                        throw new Exception("回收失败！");
                }
                catch (Exception ex)
                {
                    errorInfo += string.Format("进程：{0}无法回收。（{1}）", item.SubItems[1].Text, ex.Message);
                }
            }
            errorInfo = errorInfo == "回收选定内存时出现错误！\n\n" ? "已成功回收选定进程的内存！" : errorInfo;
            MessageBox.Show(errorInfo, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void btn管理免回收进程列表_Click(object sender, EventArgs e)
        {
            FrmNoCleanManager fncm = new FrmNoCleanManager(this.MemorySetting.NoCleanProcesses);
            fncm.ShowDialog();
        }

        #endregion

        #region “选项”选项卡

        //低内存警告等级变化时，严重低内存最大值，不能超过低内存最大值
        private void set_MemoryWarningLevel_Low_ValueChanged(object sender, EventArgs e)
        {
            if (this.set_MemoryWarningLevel_TooLow_Num.Value > this.set_MemoryWarningLevel_Low_Num.Value)
            {
                this.set_MemoryWarningLevel_TooLow_Num.Value = this.set_MemoryWarningLevel_Low_Num.Value;
            }
            this.set_MemoryWarningLevel_TooLow_Num.Maximum = this.set_MemoryWarningLevel_Low_Num.Value;
        }

        private void set_AutoCleanMemoryUnderLow_Ckb_CheckedChanged(object sender, EventArgs e)
        {
            //this.set_MemoryWarningLevel_Low_Num.Enabled = this.set_AutoCleanMemoryUnderLow_Ckb.Checked;
            //this.set_MemoryWarningLevel_TooLow_Num.Enabled = this.set_AutoCleanMemoryUnderLow_Ckb.Checked;
        }

        private void set_AutoCleanMemoryByTime_CheckedChanged(object sender, EventArgs e)
        {
            this.set_AutoCleanLevel_Num.Enabled = this.set_AutoCleanMemoryByTime_Ckb.Checked;
            this.set_AutoCleanTimeSpan_Txt.Enabled = this.set_AutoCleanMemoryByTime_Ckb.Checked;
        }

        private void set_TopWindow_Ckb_CheckedChanged(object sender, EventArgs e)
        {
            this.TopMost = this.set_TopWindow_Ckb.Checked;
        }

        //自动回收时间间隔文本框
        private void set_AutoCleanTimeSpan_Txt_TextChanged(object sender, EventArgs e)
        {
            int inputValue = 0;
            int.TryParse(this.set_AutoCleanTimeSpan_Txt.Text, out inputValue);
            if (inputValue<=0)
            {
                MessageBox.Show("自动回收时间必须为大于0的整数！\n\n请重新输入！", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.set_AutoCleanTimeSpan_Txt.Focus();
                this.set_AutoCleanTimeSpan_Txt.SelectAll();
            }
        }

        private void btn应用配置_Click(object sender, EventArgs e)
        {
            if (this.GetMemorySettingFromControl())
            {
                //执行一次
                this.SetMemorySettingToControl();
                MessageBox.Show("配置应用成功！", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
                MemorySettingManager.SaveSetting(this.MemorySetting, this.SettingFilePath);
            }
        }

        private void btn恢复默认值_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确认要恢复默认配置吗？","操作确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question)== DialogResult.Yes)
            {
                this.MemorySetting = new MemorySetting();
                this.SetMemorySettingToControl();
            }
        }

        #endregion

        #region “日志”选项卡

        private void txtLog_TextChanged(object sender, EventArgs e)
        {
            string[] rowInfoList = this.txtLog.Text.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            if (rowInfoList.Length>this.set_LogMaxRow_Num.Value)
            {
                //多余的行数
                int removeCount = (int)(rowInfoList.Length - this.set_LogMaxRow_Num.Value);

                //需要删除的文本
                string removeString = string.Empty;
                for (int i = 0; i < removeCount; i++)
                {
                    removeString += string.Format("{0}\r\n", rowInfoList[i]);
                }

                //清除
                this.txtLog.Text = this.txtLog.Text.Replace(removeString, string.Empty);
            }

            this.txtLog.Select(this.txtLog.Text.Length, 0);
        }

        private void btn保存日志_Click(object sender, EventArgs e)
        {
            try
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Title = "保存日志";
                sfd.Filter = "日志文件(*.txt,*.log)|*.txt,*.log";
                sfd.FileName = Path.Combine(Application.StartupPath, string.Format("MemoryPlusLog_{0}.txt", DateTime.Now.ToFileTime()));
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    using (FileStream fs = new FileStream(sfd.FileName, FileMode.Create, FileAccess.Write))
                    {
                        StreamWriter sw = new StreamWriter(fs, Encoding.Default);
                        sw.Write(this.txtLog.Text);
                        sw.Flush();
                        sw.Close();
                        sw.Dispose();
                    }

                    MessageBox.Show("日志保存成功！", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("日志保存失败！原因是：\n\n" + ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btn清空日志_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确定要清除日志窗口中的内容吗？",this.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question)== DialogResult.Yes)
            {
                this.txtLog.Clear();
            }
        }

        #endregion

        #endregion

        #region NotifyIcon 通知区域图标

        private void ntiMain_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                //显示或者隐藏界面
                this.ShowOrHideWindow();
            }
        }

        #endregion

        #endregion
    }
}